import {
  BeforeApplicationShutdown,
  MiddlewareConsumer,
  Module,
  OnApplicationBootstrap,
  OnApplicationShutdown,
  OnModuleDestroy,
  OnModuleInit,
} from '@nestjs/common';
import databaseConfig from './config/database.config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerModule } from './common/logger/logger.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { UserModule } from './user/user.module';
import { ServeStaticModule } from '@nestjs/serve-static';
import { BookModule } from './book/book.module';
import { LargeFileUploadModule } from './large-file-upload/large-file-upload.module';
import { SseModule } from './sse/sse.module';
import { WeatherModule } from './weather/weather.module';
import { HttpModule } from '@nestjs/axios';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './core/auth/auth.module';
import {
  CookieResolver,
  HeaderResolver,
  I18nModule,
  QueryResolver,
} from 'nestjs-i18n';
import { I18nModule as I18nModuleAlias } from './i18n/i18n.module';
import { LargeFileDownloadModule } from './large-file-download/large-file-download.module';
import { ExcelModule } from './excel/excel.module';
import { UseDbModule } from './use-db/use-db.module';
import { SessionModule } from './session/session.module';
import { JwtModule as JwtModuleAlias } from './jwt/jwt.module';
import path from 'node:path';
import { JwtModule } from '@nestjs/jwt';
import { LoginRegisterModule } from './login-register/login-register.module';
import { LogMiddleware } from './log.middleware';
import { TimerModule } from './timer/timer.module';
import { SocketModule } from './socket/socket.module';
import { OrderEmitterModule } from './order-emitter/order-emitter.module';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { QueueModule } from './queue/queue.module';
import { MongoTypeormModule } from './mongo-typeorm/mongo-typeorm.module';
import { UdpModule } from './udp/udp.module';
import { OpenaiModule } from './openai/openai.module';
import { UsingEsmPackagesModule } from './using-esm-packages/using-esm-packages.module';
import { ChildProcessModule } from './child-process/child-process.module';
import { ClientsModule, Transport } from '@nestjs/microservices';

@Module({
  imports: [
    // 连接微服务
    ClientsModule.register({
      isGlobal: true,
      clients: [
        {
          name: 'SUM_SERVICE',
          transport: Transport.TCP,
          options: {
            host: '192.168.4.70',
            port: 8888,
          },
        },
      ],
    }),
    // 事件模块，用于事件的发布和订阅
    EventEmitterModule.forRoot(),
    // 配置模块，用于加载环境变量
    ConfigModule.forRoot({
      expandVariables: true, // 启用环境变量扩展功能
      cache: true, // 启用缓存，以便在应用重启时可以加载缓存的配置
      load: [databaseConfig], // 加载数据库配置
      isGlobal: true, // 全局注册
      envFilePath:
        process.env.NODE_ENV === 'production' ? '.env.production' : '.env',
    }),
    // 配置jwt
    JwtModule.registerAsync({
      global: true,
      useFactory: async (configService: ConfigService) => {
        return {
          secret: configService.get('JWT_SECRET'),
          signOptions: { expiresIn: configService.get('JWT_EXPIRE_TIME') },
        };
      },
      imports: [ConfigModule],
      inject: [ConfigService],
    }),
    // 数据库模块，用于连接数据库
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService): object => {
        return {
          type: configService.get('database.type'),
          host: configService.get('database.host'),
          port: configService.get('database.port'),
          username: configService.get('database.username'),
          password: configService.get('database.password'),
          database: configService.get('database.database'),
          timezone: configService.get('database.timezone'),
          autoLoadEntities: true, //自动加载所有在应用中通过 TypeOrmModule.forFeature() 注册的实体类
          synchronize: configService.get('database.synchronize'), // 它会检查表是否存在，字段是否匹配，关系是否正确等，然后自动创建、修改或删除数据库表结构(开发环境下可以设置为 true，生产环境下建议设置为 false)
          logging: configService.get('database.logging'),
          poolSize: configService.get('database.poolSize'),
          connectorPackage: 'mysql2',
          extra: {
            authPlugin: 'sha256_password',
          },
        };
      },
    }),
    // 统一配置 axios
    HttpModule.register({
      timeout: 5000,
    }),
    // 日志模块，用于记录日志
    LoggerModule,
    //配置国际化
    I18nModule.forRoot({
      fallbackLanguage: 'zh',
      loaderOptions: {
        path: path.join(__dirname, '../i18n/'),
        watch: true,
      },
      resolvers: [
        new QueryResolver(['lang', 'l']), //这里是从 query 中读取，比如 ?lang=en、?l=zh
        new HeaderResolver(['x-lang']), // 这里是从 header 中读取，比如 x-lang: en
        new CookieResolver(['lang']), // 这里是从 cookie 中读取，比如 lang: en   I18nContext.current()?.lang 会自动从这里读取
      ],
    }),
    // 静态资源模块，用于 serving static files
    ServeStaticModule.forRoot(
      {
        rootPath: `${__dirname}/../public`,
        renderPath: '/',
      },
      {
        rootPath: `${__dirname}/../uploads`,
        serveRoot: '/uploads',
      },
    ),
    // 认证模块，用于处理token 认证相关的业务逻辑
    AuthModule,
    // 用户模块，用于处理用户相关的业务逻辑
    UserModule,
    // 图书模块，用于处理图书相关的业务逻辑
    BookModule,
    // 大文件分片上传
    LargeFileUploadModule,
    // 大文件下载
    LargeFileDownloadModule,
    // 服务器推送 测试模块
    SseModule,
    // 天气数据拉取 测试模块
    WeatherModule,
    // 国际化 测试模块
    I18nModuleAlias,
    // excel 解析
    ExcelModule,
    // 数据库操作模块，用于处理数据库相关的业务逻辑
    UseDbModule,
    // session测试 模块
    SessionModule,
    // jwt 测试模块
    JwtModuleAlias,
    // MySQL + TypeORM + JWT 实现登录注册
    LoginRegisterModule,
    // 测试定时器 schedule
    TimerModule,
    SocketModule,
    // 测试emitter 事件
    OrderEmitterModule,
    // 模拟队列，处理多异步任务
    QueueModule,

    // mongodb + typeorm 测试模块
    // TypeOrmModule.forRoot({
    //   type: 'mongodb',
    //   host: 'localhost',
    //   port: 27017,
    //   database: 'test',
    //   autoLoadEntities: true,
    //   synchronize: true,
    // }),
    // MongoTypeormModule,
    // 测试 udp 模块
    UdpModule,

    // 测试 openai 模块
    OpenaiModule,

    // 测试使用 esm 包模块
    UsingEsmPackagesModule,

    // 测试子进程模块
    ChildProcessModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})

// 应用模块，用于初始化应用
export class AppModule
  implements
    OnModuleInit,
    OnApplicationBootstrap,
    OnModuleDestroy,
    BeforeApplicationShutdown,
    OnApplicationShutdown
{
  async onModuleInit() {
    console.log('AppModule onModuleInit');
    const packageJsonPath = path.resolve(process.cwd(), 'package.json');
    const packageJson = require(packageJsonPath);
    console.log({
      version: packageJson.version,
      name: packageJson.name,
      author: packageJson.author,
      description: packageJson.description,
    });
  }

  async onApplicationBootstrap() {
    console.log('AppModule onApplicationBootstrap');
  }

  async onModuleDestroy() {
    console.log('AppModule onModuleDestroy');
  }

  async beforeApplicationShutdown() {
    console.log('AppModule beforeApplicationShutdown');
  }

  async onApplicationShutdown() {
    console.log('AppModule onApplicationShutdown');
  }

  // 启用 log middleware
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LogMiddleware).forRoutes('*');
  }
}
